package cn.haoxsf.app.system.service.impl;


import cn.haoxsf.app.common.api.enums.OrderExceptionEnum;
import cn.haoxsf.app.common.api.enums.SystemExceptionEnum;
import cn.haoxsf.app.common.api.enums.UserExceptionEnum;
import cn.haoxsf.app.common.constant.order.OrderConstant;
import cn.haoxsf.app.common.exception.BaseException;

import cn.haoxsf.app.common.util.DateUtil;
import cn.haoxsf.app.common.util.DistanceCalculationUtils;
import cn.haoxsf.app.common.util.RandomOrderID;
import cn.haoxsf.app.common.util.ToolUtil;
import cn.haoxsf.app.config.wechat.uuuu.WeChatTemplateMsgUtils;
import cn.haoxsf.app.pay.service.IPayInfoService;
import cn.haoxsf.app.system.dto.LoginUser;
import cn.haoxsf.app.system.entity.*;
import cn.haoxsf.app.system.mapper.OrderMapper;
import cn.haoxsf.app.system.model.param.OrderParam;
import cn.haoxsf.app.system.model.vo.BusinessResult;
import cn.haoxsf.app.system.model.vo.MemberVo;
import cn.haoxsf.app.system.service.*;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.log4j.Log4j2;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateData;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author Ele  qvbanfm@qq.com
 * @since 2020-03-17
 */
@Service
@Log4j2
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements IOrderService {
    @Autowired
    private IAuthService authService;//鉴权
    @Autowired
    private ICostService costService;//费用
    @Autowired
    private IFileInfoService fileInfoService;//上传
    @Autowired
    private IFaultItemService faultItemService;//故障详情
    @Autowired
    private IFaultCategoryService categoryService;//故障分类
    @Autowired
    private IOrderRelationService orderRelationService;//接单关系表
    @Autowired
    private IBusinessService businessService;//商户
    @Autowired
    private IMemberService memberService;//用户
    @Autowired
    private WeChatTemplateMsgUtils weChatTemplateMsgUtils;//微信模板通知
    @Autowired
    private IPayInfoService payInfoService;//支付
    @Autowired
    private IRedisService redisService;//缓存

    /**
     * 创建订单
     *
     * @param param 订单
     */
    @Override
    @Transactional
    public Order create(OrderParam param) {
        LoginUser loginUser = authService.getLoginUser();
        if (ToolUtil.isEmpty(param.getCategoryId())) {
            throw new BaseException(SystemExceptionEnum.SERVER_ERROR.getCode(), "故障类目id为空！");
        }
        //查询故障分类
        FaultCategory faultCategory = categoryService.getOne(new QueryWrapper<FaultCategory>()
                .eq("category_id", param.getCategoryId()));
        //故障类目是否开启
        if (!"ENABLE".equals(faultCategory.getCategoryState())) {
            throw new BaseException(SystemExceptionEnum.VALIDATE_FAILED.getCode(), "该分类未开启");
        }
        //价格比对
        Cost cost = costService.getOne(new QueryWrapper<Cost>().eq("fault_category_id", param.getCategoryId()));
        if (ToolUtil.isEmpty(cost)) {
            throw new BaseException(SystemExceptionEnum.VALIDATE_FAILED.getCode(), "故障类目id错误");
        }
        if (cost.getCost().compareTo(param.getPayment()) != 0) {
            log.info("费用可能被修改;数据库的值：[{}];前端出来的值：[{}]", cost.getCost(), param.getPayment());
            throw new BaseException(SystemExceptionEnum.SERVER_ERROR.getCode(), "业务异常！订单价非法");
        } else {
            // 组装数据
            Order order = new Order();
            BeanUtils.copyProperties(param, order);
            order.setPaymentType(OrderConstant.ON_LINE.getCode());//TODO 线上支付 后面需要 改动
            order.setCreateTime(new Date());
            order.setOrderNo(RandomOrderID.GetRandom());
            order.setMemberId(loginUser.getId());
            order.setOrderStatus(OrderConstant.UNPAID.getCode());//TODO 未付款 = UNPAID 后面需要 改动
            //判断订单过期时间不能大于10天
            Integer day = DateUtil.comparison(DateUtil.fomatDate(order.getExpirationTime()), "day");
            if (!ToolUtil.isEmpty(day)) {
                if (10 <= day) {
                    throw new BaseException(OrderExceptionEnum.ORDER_EXPIRED.getCode(), "订单不能超过10天");
                } else if (-1 >= day) {
                    throw new BaseException(OrderExceptionEnum.ORDER_EXPIRED.getCode(), "订单不能小于1天");
                }
            } else {
                throw new BaseException(SystemExceptionEnum.SERVER_ERROR.getCode(), "业务异常[时间转换出错]");
            }
            try {
                int insert = baseMapper.insert(order);
                if (insert > 0) {
                    payInfoService.localPay(loginUser.getId().toString(), order.getOrderNo(), order.getPayment());
                    //用户是否绑定微信
                    if (ToolUtil.isNotEmpty(loginUser.getOpenId())) {
                        List<WxMpTemplateData> listData = Arrays.asList(
                                new WxMpTemplateData("first", "支付成功-订单发布成功!", "#173177"),
                                new WxMpTemplateData("keyword1", loginUser.getNickname(), "#173177"),
                                new WxMpTemplateData("keyword2", order.getOrderNo(), "#173177"),
                                new WxMpTemplateData("keyword3", "￥" + cost.getCost().toString(), "#173177"),
                                new WxMpTemplateData("keyword4", faultCategory.getCategoryName() + ":" + order.getFaultName(), "#173177"),
                                new WxMpTemplateData("keyword5", order.getPhone()),
                                new WxMpTemplateData("keyword6", "等待接单"),
                                new WxMpTemplateData("remark", "如有疑问，请联系客服", "#173177")
                        );
                        weChatTemplateMsgUtils.sendMessageToWeChat("TkqbvuZQ_tqqlcEc2KSGJARJfqta636MvYpJzfGDD6s", loginUser.getOpenId(), listData);
                    }
                    return order;
                } else {
                    return null;
                }
            } catch (Throwable e) {
                if (e instanceof DuplicateKeyException) {
                    throw new BaseException(OrderExceptionEnum.ORDER_IS_EXIST);
                } else {
                    log.info("订单入库异常{}", e.getMessage());
                    throw new BaseException(SystemExceptionEnum.SERVER_ERROR.getCode(), "业务异常[" + e.getMessage() + "]");
                }
            }
        }
    }

    /**
     * 取消订单
     *
     * @param orderNo 订单号
     * @return 结果
     */
    @Override
    public Boolean cancel(String orderNo) {
        //查询订单
        Order order = baseMapper.selectOne(new QueryWrapper<Order>().eq("order_no", orderNo));
        //是否存在该订单
        if (ToolUtil.isEmpty(order)) {
            throw new BaseException(OrderExceptionEnum.ORDER_DOES_NOT_EXIST);
        }
        if (OrderConstant.CANCEL.getCode().equals(order.getOrderStatus())) {
            throw new BaseException(OrderExceptionEnum.ORDER_CANCELLED);
        }
        LoginUser loginUser = authService.getLoginUser();
        //是否可以取消
        //是否是已支付
        if (OrderConstant.PAID.getCode().equals(order.getOrderStatus())) {//已支付不能取消
            throw new BaseException(OrderExceptionEnum.PAID_CANNOT_BE_CANCELLED);
        }
        //是否本人操作
        if (!loginUser.getId().equals(order.getMemberId())) {
            throw new BaseException(OrderExceptionEnum.ORDER_IS_NOT_ME);
        }
        order.setOrderStatus(OrderConstant.CANCEL.getCode());
        order.setCloseTime(new Date());
        return baseMapper.updateById(order) > 0;
    }

    /**
     * 通用查询分页
     *
     * @param option 选项 为get 查询发订单,All为查询全都订单 B为查询接的订单
     * @param page   分页对象
     * @return IPage 发布者的订单集合分页
     */
    @Override
    public List<Map<String, Object>> getMyOrderPage(Page<Order> page, String option, Double lat, Double lng, String me) {
        LoginUser loginUser = authService.getLoginUser();
        if ("get".equals(option)) {//查询发布订单
            List<Map<String, Object>> myOrderPage = baseMapper.getMyOrderPage(page, loginUser.getId(), me);
            for (Map<String, Object> map : myOrderPage) {
                Member member = memberService.getById(map.get("memberId").toString());
                map.put("publisher", ToolUtil.isEmpty(member.getNickName()) ? member.getUsername() : member.getNickName());//发布者
                map.remove("memberId");
            }
            return getMaps(myOrderPage, lat, lng);
        } else if ("B".equals(option)) {//查询接单
            //查询接单关联
            Page<OrderRelation> orderRelationPage = new Page<>(page.getCurrent(), page.getSize());
            List<Map<String, Object>> mapList = orderRelationService.GetToOrder(orderRelationPage, loginUser.getId());
            if (ToolUtil.isEmpty(mapList)) {
                return null;
            }
            List<String> list = new ArrayList<>();
            for (Map<String, Object> map : mapList) {
                list.add(map.get("orderId").toString());//拼接订单id
            }

            QueryWrapper<Order> orderQueryWrapper = new QueryWrapper<>();//查询方式
            orderQueryWrapper.in("order_no", list);
            if (!"All".equals(me) && ToolUtil.isNotEmpty(me)) {//查询订单状态
                orderQueryWrapper.eq("order_status", me);
            }
            List<Map<String, Object>> allByOrderId = baseMapper.selectMaps(orderQueryWrapper);
            for (Map<String, Object> map : allByOrderId) {
                Member member = memberService.getById(map.get("memberId").toString());
                map.put("publisher", ToolUtil.isEmpty(member.getNickName()) ? member.getUsername() : member.getNickName());//发布者
                map.remove("memberId");
            }
            return getMaps(allByOrderId, lat, lng);
        } else if ("All".equals(option)) {//查询全部
            List<Map<String, Object>> myOrderPage = baseMapper.getMyOrderPage(page, null, me);
            return getMaps(myOrderPage, lat, lng);
        }
        return null;
    }

    private List<Map<String, Object>> getMaps(List<Map<String, Object>> myOrderPage, Double lat, Double lng) {
        if (ToolUtil.isEmpty(myOrderPage)) {
            throw new BaseException(SystemExceptionEnum.NOT_DATA);
        }
        for (Map<String, Object> map : myOrderPage) {
            String[] faultImageIds = map.get("faultImageId").toString().split(",");
            if (ToolUtil.isEmpty(faultImageIds)) {
                return null;
            }
            List<Map<String, Object>> faultImage = fileInfoService.selectBatchFinalNames(faultImageIds);
            if (ToolUtil.isNotEmpty(map.get("faultId").toString())) {
                String[] faultIds = map.get("faultId").toString().split(",");
                //故障详情
                List<Map<String, Object>> listByIds = faultItemService.getListByIds(faultIds);
                List<String> str = new ArrayList<>();
                Long cId = 0L;
                for (Map<String, Object> faultItem : listByIds) {
                    str.add(faultItem.get("itemName").toString());
                    cId = (Long) faultItem.get("categoryId");
                }
                map.put("faultName", ToolUtil.isEmpty(ToolUtil.getStr(str)) ? "找不到相关信息" : ToolUtil.getStr(str));
                map.put("faultCategoryName", ToolUtil.isEmpty(cId) ? "找不到相关信息" : categoryService.getById(cId).getCategoryName());
            }
            map.remove("faultImageId");
            map.put("faultImage", faultImage);

            map.remove("faultId");
            map.remove("categoryId");
            if (0 != lat || 0 != lng || ToolUtil.isEmpty(map.get("latitude").toString()) || ToolUtil.isEmpty(map.get("longitude").toString())) {//计算距离
                map.put("distance", DistanceCalculationUtils.getDistance(lat, lng, (Double) map.get("latitude"), (Double) map.get("longitude")));
            } else {
                map.put("distance", null);
            }
        }
        return myOrderPage;
    }

    /**
     * 接单
     *
     * @param orderNo
     * @return
     */
    @Override
    @Transactional
    public Order receipt(String orderNo) {
        LoginUser loginUser = authService.getLoginUser();
        Order order = baseMapper.selectOne(new QueryWrapper<Order>().eq("order_no", orderNo));
        MemberVo business = memberService.getMemberAndBusinessByUsername(loginUser.getUsername());
        if (ToolUtil.isEmpty(business)) {
            throw new BaseException(SystemExceptionEnum.SERVER_ERROR.getCode(), "商户信息错误！请联系客户！");
        }
        //是否是自己订单
        if (loginUser.getId().equals(order.getMemberId())) {
            throw new BaseException(OrderExceptionEnum.CAN_T_TAKE_YOUR_ORDER);
        }
        if (ToolUtil.isNotEmpty(order) && !"CANCEL".equals(order.getOrderStatus())) {
            //订单是否已支付
            if ("UNPAID".equals(order.getOrderStatus())) {
                throw new BaseException(OrderExceptionEnum.ORDER_NOT_PAID);
            }
            //是否是师傅和是否开工
            if ("OFF".equals(business.getBusiness().getWorkState())) {
                throw new BaseException(UserExceptionEnum.NOT_STARTED);
            }
            //是否是已接单
            if ("RECEIVED".equals(order.getOrderStatus())) {
                throw new BaseException(OrderExceptionEnum.ORDER_RECEIVED);
            }
            //修改订单状态
            order.setOrderStatus("RECEIVED");//已接单
            order.setStartTime(new Date());//接单时间
            baseMapper.updateById(order);
            //写入关联
            orderRelationService.createRelation(loginUser.getId(), order.getOrderNo());
            //查询出发单者
            Member member = memberService.getById(order.getMemberId());
            String randomNumber = ToolUtil.getRandomNumber(4);
            //是否绑定微信
            if (ToolUtil.isEmpty(member.getOpenId())) {
                //TODO 没有绑定微信 短信通知
            } else {
                //生成完成码
                List<WxMpTemplateData> listData = Arrays.asList(
                        new WxMpTemplateData("completeCode", randomNumber, "#173177"),
                        new WxMpTemplateData("businessPhone", business.getPhone(), "#173177"),
                        new WxMpTemplateData("businessName", business.getBusiness().getRealName(), "#173177")
                );
                weChatTemplateMsgUtils.sendMessageToWeChat("WCDzrtsw-cBjCdf03KK8jj2x5p6WiOYqnvpXYns782Y", member.getOpenId(), listData);
                //TODO  短信通知
            }
            //缓存完成码 TODO 时间格式
            Integer day = DateUtil.comparison(DateUtil.fomatDate(order.getExpirationTime()), "day");
            if (!ToolUtil.isEmpty(day)) {
                if (10 <= day) {//订单不能大于10天
                    throw new BaseException(OrderExceptionEnum.ORDER_EXPIRED.getCode(), "订单不能超过10天");
                }
            } else {
                throw new BaseException(SystemExceptionEnum.SERVER_ERROR.getCode(), "业务异常[时间转换出错]");
            }
            int i = day * 60 * 24;
            redisService.setString(order.getOrderNo(), randomNumber, i);
        } else {
            throw new BaseException(OrderExceptionEnum.ORDER_DOES_NOT_EXIST);
        }
        return order;
    }

    /**
     * 完成订单
     *
     * @param orderNo 订单号
     */
    @Override
    @Transactional
    public void completeOrder(String orderNo) {
        LoginUser loginUser = authService.getLoginUser();//当前商户
        //查询订单关系
        OrderRelation orderRelation = orderRelationService.getOne(new QueryWrapper<OrderRelation>().eq("order_id", orderNo));
        if (ToolUtil.isNotEmpty(orderRelation)) {
            Order order = this.baseMapper.selectOne(new QueryWrapper<Order>().eq("order_no", orderRelation.getOrderId()));
            if (ToolUtil.isNotEmpty(order)) {
                //订单不能过期
                if (new Date().getTime() > order.getExpirationTime().getTime()) {
                    throw new BaseException(OrderExceptionEnum.ORDER_EXPIRED);
                } else {
                    MemberVo business = memberService.getMemberAndBusinessByUsername(loginUser.getUsername());
                    //订单是已支付 和已接单
                    if (OrderConstant.RECEIVED.getCode().equals(order.getOrderStatus())) {
                        //修改订单状态
                        order.setOrderStatus(OrderConstant.SUCCESS.getCode());
                        //向商户打款
                        if (ToolUtil.isNotEmpty(business.getBusiness())) {//商户是否存在
                            Member member = new Member();
                            BeanUtils.copyProperties(business, member);
                            //获取订单价格
                            BigDecimal add = order.getPayment().add(member.getMemberMoney());//订单价格加上原有得金额
                            member.setMemberMoney(add);
                            UpdateWrapper<Member> wrapper = new UpdateWrapper<>();
                            wrapper.eq("username", member.getUsername());
                            memberService.update(member, wrapper);
                        }
                        //入库
                        //完成时间
                        order.setEndTime(new Date());
                        this.baseMapper.updateById(order);
                        //TODO 通知
                    }else {
                        throw new  BaseException(OrderExceptionEnum.ORDER_NO_UPDATE);
                    }
                }
            }
        }else {
            throw new BaseException(OrderExceptionEnum.ORDER_NO_UPDATE);
        }
    }
}
